import { isBlob, isValidUrl } from "./is"

// 节流适用于持续的触发
// 防抖适用于短时间内的大量触发
interface IDToptions {
  leading?: boolean
}
// 节流函数
// 定义：在一段时间内最多触发一次事件。当事件持续触发时，每n秒只执行一次函数。如果在n秒内事件被重复触发，那么只有第一次触发的事件会生效，一段时间过后才能再次触发。
// 场景：主要用于一些高频的事件，比如鼠标的scroll事件或者mousemove事件等。如果没有节流，事件会频繁触发，进而影响性能。此外，还常用于处理如浏览器播放事件、window的resize等场景
// 场景: 鼠标拖拽、鼠标滚轴滚动 窗口resize
export function HsThrottle(fn: (...args: any) => any, delay: number = 250, options?: IDToptions): any {
  options = options || { leading: false }
  let timer:number = null as any
  let leading = false
  if (options?.leading) {
    leading = options?.leading
  }

  return function (this: any, ...args: any) {
    if (timer !== null) {
      return
    }
    // 先执行,然后进行节流
    if (leading) {
      fn.apply(this, args)
      timer = setTimeout(() => {
        clearTimeout(timer)
        timer = null as any
      }, delay)
    } else {
      timer = setTimeout(() => {
        clearTimeout(timer)
        timer = null as any
        fn.apply(this, args)
      }, delay)
    }
  }
}

// 防抖函数
// 定义：在一段时间内，只要有事件触发，就重新计算时间，直到这段时间内没有事件触发，才真正执行事件函数。如果在等待执行函数的过程中又触发了新的事件，那么将取消之前的计时并重新开始计时，直到等待的时间结束且没有新的事件触发时，才执行事件函数。1234
// 场景：适用于一些用户输入的事件，比如搜索框输入时触发请求。如果用户连续输入字符，防抖可以确保在用户停止输入后才发起请求，避免短时间内的频繁请求，提高性能。此外，还常用于短信验证、文本编辑器实时保存等场景。
// 场景: 搜索、
export function HsDebounce(fn: (...args: any) => any, delay: number = 250): any {
  let timer: number = null as any
  return function (this: any, ...args: any) {
    if (timer !== null) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      clearTimeout(timer)
      timer = null as any
      fn.apply(this, args)
    }, delay)
  }
}

// Unit8Array 数据流转化为字符串, 兼容汉字
export function Utf8ArrayToStr(array: Uint8Array): string {
  let out = "",
    i = 0,
    char1,
    char2,
    char3,
    char4
  const len = array.length
  while (i < len) {
    char1 = array[i++]
    // 当单个字节时, 最大值 '01111111', 最小值 '00000000' 右移四位 07, 00
    // 当两个字节时, 最大值 '11011111', 最小值 '11000000' 右移四位 13, 12
    // 当三个字节时, 最大值 '11101111', 最小值 '11100000' 右移四位 14, 14
    if (char1 >> 4 <= 7) {
      out += String.fromCharCode(char1)
    } else if (char1 >> 4 == 12 || char1 >> 4 == 13) {
      char2 = array[i++]
      out += String.fromCharCode(((char1 & 0x1f) << 6) | (char2 & 0x3f))
    } else if (char1 >> 4 == 14) {
      char2 = array[i++]
      char3 = array[i++]
      char4 = ((char1 & 0x0f) << 12) | ((char2 & 0x3f) << 6)
      out += String.fromCharCode(char4 | ((char3 & 0x3f) << 0))
    }
  }
  return out
}

export function HsDeepCopy<T extends object>(data: T): T {
  return JSON.parse(JSON.stringify(data))
}

export function HsDelayFn(delay: number = 250) {
  return new Promise((resolve) => {
    const timer = setTimeout(() => {
      clearTimeout(timer)
      resolve(true)
    }, delay)
  })
}

export const saveUrlAsFile = (url:string = '', fileName?:string, ext?:string) => {
  fileName = fileName ?? '模板'
  ext = ext ?? '.xlsx'
  let link = document.createElement("a")
  link.style.display = "none"
  link.download = `${fileName}${ext}`
  link.href = url
  link.click()
  link = null!
}

export const saveAsJson = (jsonData = {}, fileName = "文件") => {
  const jsonDataStr = JSON.stringify(jsonData)
  const blob = new Blob([jsonDataStr], { type: "application/json;charset=utf-8" })
  const url = URL.createObjectURL(blob)
  let link = document.createElement("a")
  link.style.display = "none"
  link.download = fileName
  link.href = url
  link.click()
  link = null!
  URL.revokeObjectURL(url)
}

export const saveBlobAsExcel = (data: Blob, fileName = "文件.xlsx") => {
  if (!data) return
  if (!isBlob(data)) return
  const blobData = data
  const blob = new Blob([blobData], {
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"
  })
  // const blob = new Blob([blobData])
  const url = URL.createObjectURL(blob)
  let link = document.createElement("a")
  link.style.display = "none"
  link.download = fileName
  link.href = url
  link.click()
  link = null!
  URL.revokeObjectURL(url)
}

export const saveUrlAsFileWithWindowOpen = (fileUrl = "", fileName?:string) => {
  if (!fileUrl) return
  if(isValidUrl(fileUrl)) {
    window.open(fileUrl)
    return 
  }
  const href = location.origin + `/sim/service/${fileUrl}`
  window.open(href)
}

// 尽量不适用eval, 打包会有警告
export function hsEval(fn: any) {
  const tmpFn = Function
  return new tmpFn(`return ${fn}`)()
}
